package objects;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;

import common.GameServer;
import common.LoadingData;
import common.Maths;

public class Map {

    private int id, posX, posY, width, height, subarea, MaxMonsterByGroup, MaxGroup;
    private boolean monsterLoaded;
    private String mapData, key, date;
    private Hashtable<Long, Character> characterOnMap = new Hashtable<Long, Character>();
    private TreeMap<Short, Cell> cellsDatas = new TreeMap<Short, Cell>();
    private TreeMap<Short, Trigger> triggersDatas = new TreeMap<Short, Trigger>();
    private Hashtable<Long, MonsterGroup> monstersOnMap = new Hashtable<Long, MonsterGroup>();
    private Hashtable<Long, Fight> fightOnMap = new Hashtable<Long, Fight>();
    private ArrayList<Short> placesTeamOne = new ArrayList<Short>();
    private ArrayList<Short> placesTeamTwo = new ArrayList<Short>();

    public Map() {
    }

    public Map(int mapID, int mapPosX, int mapPosY, int mapWidth, int mapHeight, int mapSubarea, String mapDate, String mapDatas, String mapKey, String pPlaces) {
        id = mapID;
        posX = mapPosX;
        posY = mapPosY;
        width = mapWidth;
        height = mapHeight;
        subarea = mapSubarea;
        date = mapDate;
        mapData = mapDatas;
        key = mapKey;
        parsePlaces(pPlaces);
        monsterLoaded = false;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getPosX() {
        return posX;
    }

    public void setPosX(int posX) {
        this.posX = posX;
    }

    public int getPosY() {
        return posY;
    }

    public void setPosY(int posY) {
        this.posY = posY;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getSubarea() {
        return subarea;
    }

    public void setSubarea(int subarea) {
        this.subarea = subarea;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getMapData() {
        return mapData;
    }

    public void setMapData(String mapData) {
        this.mapData = mapData;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public int getFightCount() {
        return fightOnMap.size();
    }

    public Hashtable<Long, Character> getCharacterOnMap() {
        return characterOnMap;
    }

    public void addCharacterOnMap(Character pCharacter) {
        this.characterOnMap.put(pCharacter.getEntitieMapGuid(), pCharacter);
    }

    public void deleteCharacterOnMap(Character pCharacter) {
        this.characterOnMap.remove(pCharacter.getEntitieMapGuid());
    }

    public void createCells() {
        DecompileMapData(mapData);
    }

    public void setCellsDatas(TreeMap<Short, Cell> cellsDatas) {
        this.cellsDatas = cellsDatas;
    }

    public TreeMap<Short, Cell> getCellsDatas() {
        return cellsDatas;
    }

    public void createTriggers() {
        Iterator<Trigger> vIter = LoadingData.getMapTriggerData().values().iterator();
        Iterator<Integer> kIter = LoadingData.getMapTriggerData().keySet().iterator();

        while (vIter.hasNext() && kIter.hasNext()) {
            Trigger valueI = vIter.next();
            int keyI = kIter.next();

            if (valueI.getCurrentMapID() == id) {
                GameServer.writeLine("Add trigger id " + keyI + " from map " + valueI.getCurrentMapID() + " at cell " + valueI.getCurrentCellID() + " to " + valueI.getToMapID() + " at cell " + valueI.getToCellID());
                LoadingData.getMapData().get(id).getTriggersDatas().put(valueI.getCurrentCellID(), valueI);
            }
        }
    }

    public void setTriggersDatas(TreeMap<Short, Trigger> pTriggersDatas) {
        this.triggersDatas = pTriggersDatas;
    }

    public TreeMap<Short, Trigger> getTriggersDatas() {
        return triggersDatas;
    }
    
    public Hashtable<Long, MonsterGroup> getMonstersOnMap()
    {
    	return monstersOnMap;
    }
    
    public void addMonsterGroupOnMap(MonsterGroup pMonsterGroup)
    {
    	if(pMonsterGroup != null)
    		monstersOnMap.put(pMonsterGroup.getEntitieMapGuid(), pMonsterGroup);
    }
    
    public void addFightOnMap(Fight fight)
    {
    	if(fight != null)
    		fightOnMap.put(fight.getGuid(), fight);
    }
    
    public Hashtable<Long, Fight> getFightOnMap()
    {
    	return fightOnMap;
    }
    
	public int getMaxGroup() {
		return MaxGroup;
	}

	public void setMaxGroup(int maxGroup) {
		MaxGroup = maxGroup;
	}
	
	public int getMaxMonsterByGroup() {
		return MaxMonsterByGroup;
	}

	public void setMaxMonsterByGroup(int maxMonsterByGroup) {
		MaxMonsterByGroup = maxMonsterByGroup;
	}
    
    public void DecompileMapData(String dData) {
        for (int f = 0; f < dData.length(); f += 10) {
            String CellData = dData.substring(f, f + 10);
            List<Byte> CellInfo = new ArrayList<Byte>();
            for (int i = 0; i < CellData.length(); i++) {
                CellInfo.add((byte) Cell.getIntByHashedValue(CellData.charAt(i)));
            }
            int Type = (CellInfo.get(2) & 56) >> 3;
            boolean IsSightBlocker = (CellInfo.get(0) & 1) != 0;
            int layerObject2 = ((CellInfo.get(0) & 2) << 12) + ((CellInfo.get(7) & 1) << 12) + (CellInfo.get(8) << 6) + CellInfo.get(9);
            boolean layerObject2Interactive = ((CellInfo.get(7) & 2) >> 1) != 0;
            int obj = (layerObject2Interactive ? layerObject2 : -1);
            cellsDatas.put(Short.parseShort(Integer.toString(f / 10)), new Cell(Short.parseShort(Integer.toString(f / 10)), Type != 0, IsSightBlocker, obj));
        }
    }
	
	public short getRandomCellID()
	{	
		if(cellsDatas.isEmpty() || cellsDatas == null)
		{
			GameServer.writeLine("Cells Data empty or null");
			return 50;
		}
		else
		{
			return cellsDatas.get(Short.parseShort(Integer.toString(Maths.randomBetween(1, cellsDatas.size())))).getGuid();
		}
	}

	public boolean isMonsterLoaded() {
		return monsterLoaded;
	}

	public void setMonsterLoaded(boolean monsterLoaded) {
		this.monsterLoaded = monsterLoaded;
	}

	public ArrayList<Short> getPlacesTeamOne() {
		return placesTeamOne;
	}

	public void addPlacesTeamOne(Short cellID) {
		this.placesTeamOne.add(cellID);
	}

	public ArrayList<Short> getPlacesTeamTwo() {
		return placesTeamTwo;
	}

	public void addPlacesTeamTwo(Short cellID) {
		this.placesTeamTwo.add(cellID);
	}
	
	public void generatePlaces()
	{
		short rCellID;
		ArrayList<Short> usedPlaces = new ArrayList<Short>();
		
		// Team 1
		for(int i = 0;i < 8;i++)
		{
			do
			{
				rCellID = getRandomCellID();
			}while(!getCellsDatas().get(rCellID).isWalkable() && !usedPlaces.contains(rCellID));
			
			usedPlaces.add(rCellID);
			addPlacesTeamOne(rCellID);
		}
		
		// Team 2
		for(int i = 0;i < 8;i++)
		{
			do
			{
				rCellID = getRandomCellID();
			}while(!getCellsDatas().get(rCellID).isWalkable() && !usedPlaces.contains(rCellID));
			
			usedPlaces.add(rCellID);
			addPlacesTeamTwo(rCellID);
		}
	}
	
	public void parsePlaces(String places)
	{
		if(places.isEmpty())return;
		String[] teams = places.split("\\|");
		
		String teamOne = teams[0];
		String teamTwo = teams[1];
		
		for(int i = 0;i < teamOne.length()-2;i += 2)
		{
			
			addPlacesTeamOne(Cell.decodeCellID(teamOne.substring(i, i+2)));
		}
		
		for(int i = 0;i < teamTwo.length()-2;i += 2)
		{
			
			addPlacesTeamTwo(Cell.decodeCellID(teamTwo.substring(i, i+2)));
		}
	}
	
	public String getFightPlaces()
	{
		Iterator<Short> pIterOne = placesTeamOne.listIterator();
		String teamOne = "";
		
		while(pIterOne.hasNext())
		{
			short place = pIterOne.next();
			
			teamOne += Cell.encodeCellID(place);
		}

		Iterator<Short> pIterTwo = placesTeamTwo.listIterator();
		String teamTwo = "";
		
		while(pIterTwo.hasNext())
		{
			short place = pIterTwo.next();
			
			teamTwo += Cell.encodeCellID(place);
		}
		
		return teamOne + "|" + teamTwo;
	}
	
}